\chapter{LCV Software-Entwicklung}\label{chap:softwareentwicklung}
\section{Überblick}
Diese Anleitung soll einen einfachen Einstieg in die Software-Entwicklung für das LCV-Board ermöglichen. Sie vermittelt Grundkenntnisse über das Board und das Framework und bietet Hilfestellung für die häufigsten Probleme.
Teilweise basiert diese Anleitung auf Informationen aus dem Documentation Wiki auf der Blackfin Webseite\cite{blackfin-wiki}.

\section{Das Zielsystem}
Beim Zielsystem handelt es sich um einen Embedded System mit einen Blackfin-Prozessor (BF537), einer Kamera (CMOS Sensor MT9V032), zwei Atmel SPI Dataflashes (je 4MB), einem Ethernetanschluss (100MBit/s) und einer RS232 Schnittstelle mit zwei zusätzlichen  In-Ports und Out-Ports. Als Betriebssystem wird uClinux verwendet. Für die C-Programmierung steht die uClibc\cite{uclib} , eine für Embedded-Systeme konzipierte C-Bibliothek, zur Verfügung. Um auf dem Zielsystem lauffähige Programme zu erstellen müssen diese mit der Blackfin-Toolchain Cross-Compiliert werden.
Da in der Originaldokumentation die Information über die Pinbelegung der RS232 Schnittstelle nur schwer zugänglich ist, folgt hier noch eine erklärende Grafik:
\begin{center}
 \includegraphics[width=300pt]{RS232.png}
 \mycaption{figure}{Pinbelegung der RS232 Schnittstelle}
\end{center}

\section{LCV Framework}
Das Framework stellt Grundfunktionen bereit. Eine Kurzreferenz befindet sich im Anhang der Dokumentation. Eine detailliertere Beschreibung der Funktionen und dem Aufbau der Strukturen (insbesondere der LCV-Bilder) befindet sich im Abschnitt Resultate (\ref{chap:resultate}). Das Framework soll aber kein starres Gebilde sein, sondern laufend verbessert und erweitert werden. Jeder Entwickler kann weitere Funktionen in das Framework integrieren oder neue Module hinzufügen. Damit neue Funktionen problemlos benutzt werden können müssen diese entsprechend getestet werden (etwa durch Erweitern des bestehenden Testprogramms).

\section{Entwicklung}

\section{Entwicklung ohne Zielsystem}
Ein LCV-Programm kann ganz ohne Zielsystem entwickelt werden. Alles was man dazu braucht ist der GNU-C-Compiler (gcc). Bei der Entwicklung ohne LCV-Board muss das Verhalten der Umwelt allerdings vom Programmierer simuliert werden. Dazu gehören beispielsweise Kamerabilder oder Hardware-Inputs der GPIO-Pins. Das Framework stellt entsprechende Funktionen zur Verfügung. Damit das Hostprogramm auch auf dem Zielsystem einwandfrei läuft sind einige Einschränkungen zu Beachten:
\begin{itemize}
\item Die uClibc auf dem Zielsystem bietet nur einen beschränkten Umfang der C-Standardbibliotheken.
\item Der Blackfin-Compiler ist nicht so tolerant wie der gcc und es gibt einige systembedingte Unterschiede (siehe dazu im Kapitel \textit{Systemunterschiede in der Dokumentation (\ref{sec:systemunterschiede})}). 
\item Für die Erstellung eines Prozesses muss vfork() anstatt fork() benutzt werden. 
\end{itemize}

\section{Entwicklung mit dem Zielsystem}
Für die Entwicklung auf dem Zielsystem wird der Blackfin Cross Compiler benötigt. Entsprechende Anleitungen zur Installation oder Kompilierung der Toolchain finden sich auf dem Blackfin Documentation Wiki\cite{blackfin-wiki}.
Damit Programme fest in die uClinux Distribution eingebunden werden können, werden auch die Quellen der für die Blackfin Architektur portierten uClinux Distribution benötigt. Diese können entweder als Stable Releases auf der entsprechenden Webseite\cite{blackfin-uclinux-release} oder als Live Sources gemäss der Anleitung \cite{uclinux-live-sources} im Blackfin Dokumentation Wiki heruntergeladen werden. \\
Für systemspezifischen Code (beispielsweise die Simulation) kann mit den Defines \textbf{LCV\_TARGET} und \textbf{LCV\_HOST} unterschieden werden, auf welchem System man sich befindet.

\subsection{Datentransfer zwischen Ziel- und Hostsystem}
Um z.B kompilierte Programme zu Testzwecken auf das LCV-Board zu laden existieren zwei Möglichkeiten:
\begin{description}
\item[Seriell] Es können Dateien im Terminal über das serielle Interface verschickt werden, dafür werden die Zmodem Tools (\ref{sec:zmodem}) benötigt. Die Anleitung bezieht sich auf das Senden und Empfangen von Dateien mit dem Minicom Terminalprogramm.
	\begin{description}
	\item[Dateien senden] Während dem Sendevorgang sind keine Konsoleneingaben möglich. Als erstes muss auf dem Zielsystem lrz gestartet werden:
\begin{verbatim}
root:~> lrz                                                                    
lrz waiting to receive.**B0100000023be50
\end{verbatim}
Mit \textit{CTRL-A + S} Wir der Dialog zur Datenübertragung geöffnet. Unter \textit{Upload} muss \textit{zmodem} gewählt werden. Nach der Auswahl der gewünschten Datei(en) mit der Leertaste wird der Sendevorgang mit \textit{Enter} initialisiert. Es erscheint ein Dialog in folgender Form:
\begin{verbatim}
+-----[zmodem Upload - Drücken Sie Strg-C zum Verlassen]------+       
|Sende: prog_target                                           |       
|Bytes gesendet:  48128   BPS:7048                            |       
|Sende:                                                       |       
|Ymodem Sektoren/Kilobytes gesendet:   0/ 0k                  |       
|Übertragung abgeschlossen                                    |       
|                                                             |       
| Fertig: Drücken Sie eine beliebige Taste zum fortfahren...  |       
+-------------------------------------------------------------+
\end{verbatim}
Die Datei befindet sich nun im aktuellen Verzeichnis und die Konsole ist wieder verfügbar.
	\item[Dateien empfangen] Um Dateien vom LCV Board an das Hostsystem zu senden, kann folgende Befehlssequenz verwendet werden: \begin{verbatim}root:~> lsz  <Dateiname>\end{verbatim} die Datei wird von Minicom automatisch empfangen und im aktuellen Verzeichnis gespeichert.
    \end{description}
\item[Ethernet (FTP)] Das LCV Board bietet ebenfalls FTP Zugriff:
\begin{verbatim}
host> ftp 192.168.0.1
username : root
password : uClinux
ftp> binary
ftp> put <Dateiname>
ftp> quit
\end{verbatim}
\end{description}

Dateien, die auf das LCV Board übertragen werden befindet sich danach im RAM der uClinux Distribution und sind nach einem Neustart oder Reset des LCV Boards nicht mehr verfügbar.

\subsection{Debuggen}
Sofern im uClinux Kernel der gdbserver installiert ist, kann über Ethernet remote Debugging betrieben werden.  Eine  Anleitung zu  remote Debugging ist in der Anleitung \textit{Entwickeln mit Eclipse} (\ref{chap:eclipse}) zu finden.

\subsection{Makefile}
Das Makefile ist universell einsetzbar. Für die Verwendung müssen aber einige Aspekte erklärt werden:\\
Grundsätzlich werden alle Source Dateien im Stammverzeichnis des Makefiles mitkompiliert. Das Framework wird modulweise zu den Quellen hinzugefügt. Wenn einzelne Module nicht benötigt werden, können diese (sofern keine weiteren Modulabhängigkeiten bestehen) bedenkenlos entfernt werden.

Grundsätzlich müssen folgende Zeilen im Makefile angepasst werden:
\begin{verbatim}
EXEC = prog
HOST_SUFFIX = _host
TARGET_SUFFIX = _target
\end{verbatim}

\begin{description}
\item[EXEC] Der Name der ausführbaren Datei.
\item[HOST\_SUFFIX] Für das Hostsystem kann dem Programmnamen ein Suffix angefügt werden (optional).
\item[TARGET\_SUFFIX] Für das Zielsystem kann dem Programmnamen ein Suffix angefügt werden (optional).
\end{description}


\subsubsection{Make Targets}
Es sind diverse Make Targets definiert, die wichtigsten für die Programmentwicklung sind:
\begin{description}
\item[target] Kompiliert das Programm inklusive LCV Framework mit dem Blackfin Cross Compiler für das Zielsystem.
\item[host] Kompiliert das Programm inklusive LCV Framework mit dem GCC für das Hostsystem.
\item[clean] Löscht alle während der Kompilierung erstellten Dateien.
\item[all] Diese Direktive könnte für Verwirrung sorgen, da effektiv nur für das Targetsystem kompiliert wird. Der Grund für den Namen liegt darin, dass bei der Kernelkompilierung dieses Target benötigt wird.
\item[romfs] Auch dieses Make Target ist für die Kernelkompilierung gedacht und kopiert die ausführbare Datei in das \textit{/bin} Verzeichnis der uClinux Distribution.
\end{description}

\subsubsection{Compiler Flags}
\begin{description}
\item[Hostsystem] Für das Hostsystem wurden folgende Compiler Flags gesetzt:
	\begin{description}
	\item[-O2] Alle optimization Flags werden eingeschaltet.
	\end{description}
\item[Zielsystem] Für das Zielsystem wurden folgende Compiler Flags gesetzt:
	\begin{description}
	\item[-ggdb3] Mehr Informationen für den GNU Debugger, je nach Programm können die Debuginformationen die Grösse der Datei allerdings drastisch verändern.
	\item[-Wl,-elf2flt] Der Blackfin Compiler generiert als erstes Assembly Code, der Blackfin Assembler generiert daraus Executable and Linkable Format (ELF) Objekt Dateien, die danach in das FLAT Binär Format umgewandelt werden müssen, damit das Programm unter uClinux ausführbar ist.
	\end{description}
\end{description}

Zusätzlich wurden zwei  Präprozessor Direktiven  definiert: \textbf{LCV\_TARGET} und \textbf{LCV\_HOST}. Die Direktiven werden je nach Kompiliertarget dem Compiler mitgegeben. \\
Die Direktiven sind zur Verwendung im Programmcode gedacht, und zwar in folgender Form:
\begin{verbatim}
#ifdev LCV_TARGET
       /* für das LCV Board gedachter Programmcode */
#ifdev LCV_HOST
       /* für den Host gedachter Programmcode */
\end{verbatim}

\section{Einbinden in die Distribution} 
Um ein Programm in die Distribution einzubinden sind mehrere Schritte notwendig.

\subsection{Hinzufügen der Quellen}
Zuerst muss ein neues Verzeichnis im \textit{user} Unterordner der verwendeten uClinux Distribution erstellt werden. Darin werden alle Quelldateien des Programmes inklusive Makefile abgelegt.
Wenn das Programm beispielsweise \textit{testapplikation} heisst, wäre ein möglicher Pfad: \textit{../uClinux-dist/user/testapplikation}.

\subsection{Anpassen der Konfiguration}
Als nächstes müssen die Make- und Konfigurationsdateien der Distribution angepasst werden:
In der Datei \textit{…/uClinux-dist/user/Makefile} muss eine Zeile nach folgendem Muster am entsprechenden Ort eingefügt werden:
\begin{alltt}
dir_\$(CONFIG_USER_TESTAPPLIKATION) += testapplikation
\end{alltt}

Danach muss die Datei \textit{…/uClinux-dist/config/Configure.help} editiert werden. Die Datei enthält den Text der bei der Kompilierung im Hilfe-Dialog angezeigt wird wenn uClinux kompiliert wird.
Der Eintrag hat folgende Form:

\begin{verbatim}
CONFIG_USER_TESTAPPLIKATION
  Das ist ein Testprogramm
\end{verbatim}

Jede Zeile Hilfetext muss mit zwei Leerzeichen eingerückt sein, ausserdem darf die Zeile nicht mehr als 70 Zeichen enthalten.\\

Zuletzt muss noch die Datei \textit{…/uClinux-dist/config/config.in} angepasst werden. Die Einträge in dieser Datei legen fest, unter welcher Sektion das Programm im Applikationskonfigurationsfenster zur Auswahl angezeigt wird.
Die einzelnen Sektionen werden durch Einträge in folgender Form abgetrennt:
\begin{verbatim}
mainmenu_option next_comment
comment 'Miscellaneous Applications'
\end{verbatim}

\begin{verbatim}
bool 'testapplikation'  CONFIG_USER_TESTAPPIKATION
\end{verbatim}

Damit sind alle Änderungen an den nötigen Dateien vorgenommen. Zu beachten ist noch, dass das Makefile einem vorgegebenen Muster folgen muss:
\begin{alltt}
EXEC = testapplikation
OBJS = testapplikation.o
all: \$(EXEC)
\$(EXEC): \$(OBJS)
        \$(CC) \$(LDFLAGS) -o \$@ \$(OBJS) \$(LDLIBS)
romfs:
        \$(ROMFSINST)    /bin/\$(EXEC)
clean:
        rm -f \$(EXEC) *.elf *.gdb *.o

\end{alltt}

Das Makefile des LCV Framworks wurde bereits auf dieses Muster abgestimmt.

\subsection{Kompilieren des Kernels}
Die Kompilation des Kernels erfolgt in drei Schritten:
\begin{enumerate}
\item make xconfig (oder make menuconfig) 
\item make dep
\item make
\end{enumerate}
Mit \textit{make menuconfig} (oder \textit{make xconfig}) wird der Konfigurationsdialog des Kernels gestartet.
Als erstes muss die Zielarchitektur ausgewählt werden:
\begin{center}
 \includegraphics[width=450pt]{menuconfig_vendor.png}
 \mycaption{figure}{Kernelkonfigurationsdialog - Vendor Selektion}
\end{center}
Unter \textit{Analog Devices} muss die \textit{BF537-LCV} Architektur ausgewählt werden.\\

Um das zu den Quellen hinzugefügte Programm in den Kernel einzubinden, sind folgende Schritte zu tätigen:
Unter \textit{Kernel/Library/Defaults Selection} den Menüpunkt \textit{Customize Vendor/User Settings (NEW)} anwählen.
\begin{center}
 \includegraphics[width=450pt]{menuconfig_usersettings_selection.png}
 \mycaption{figure}{Kernelkonfigurationsdialog - Vendor/User Settings anpassen}
\end{center}
Anschliessend kann das Konfigurationsmenü über Exit (2x) verlassen werden. Die Frage, ob man die neue Kernelkonfiguration speichern will mit ''Yes'' antworten.
Danach wird automatisch der Dialog zur Auswahl der Programme aufgerufen.
\begin{center}
 \includegraphics[width=450pt]{menuconfig_mainmenu.png}
 \mycaption{figure}{Kernelkonfigurationsdialog - Hauptmenü}
\end{center}
Je nachdem, wo sich in der Datei\textit{ …/uClinux-dist/config/config.in} der Konfigurationseintrag des eigenen Programmes befindet, wird das Programm im entsprechenden Untermenü zur Auswahl aufgelistet. Nach der Selektion des Programmes kann auch dieses Konfigurationsmenü verlassen und die neue Konfiguration gespeichert werden.
\\
Die nächsten Schritte sind simpel:
\begin{alltt}
bash\$ make dep
bash\$ make
\end{alltt}
Mit \textit{make dep} werden die Abhängigkeiten generiert und mit \textit{make} der Kernel kompiliert. \\
Der Name des für das LCV Board geeigneten Images lautet \textbf{uImage}. \\

Nach erfolgreicher Kompilation wird das Image des Kernels automatisch in das Verzeichnis \textit{/tftpboot} abgelegt, vorausgesetzt der TFTP Server ist installiert und das entsprechende Verzeichnis mit den korrekten Zugriffsrechten angelegt.

\subsection{Installation des Kernels}
Voraussetzung für die Installation des Kernels auf dem LCV Board sind ein funktionierender TFTP Server auf dem Hostsystem und eine Serielle- sowie Ethernetverbindung mit dem LCV Board.\\

Der Host muss mit den folgenden Ethernet Einstellungen konfiguriert sein:
\begin{description}
\item[IP-Adresse] 192.168.0.3 
\item[Netzwerkmaske] 255.255.255.0
\end{description}
Diese Einstellungen hängen von der Konfiguration von U-Boot, dem LCV Bootloader ab.\\

Wird das Board neu gestartet erscheint auf dem Terminal eine Anzeige in folgender Form:
\begin{verbatim}
icache_enable
U-Boot 1.1.6-svn (ADI-2007R1) (Sep 18 2007 - 20:30:23)

CPU:   ADSP BF537 Rev.: 0.2
Board: ADI BF537 Low Cost Vision (LCV) board
       Support: http://blackfin.uclinux.org/
Clock: VCO: 500 MHz, Core: 500 MHz, System: 125 MHz
SDRAM: 64 MB
DataFlash:AT45DB321
Nb pages:   8192
Page Size:    512
Size= 4194304 bytes
Logical address: 0x10000000
Area 0: 10000000 to 10007FFF
Area 1: 10008000 to 1001FFFF
Area 2: 10020000 to 10027FFF
Area 3: 10028000 to 103FFFFF
In:    serial
Out:   serial
Err:   serial
Net:    BF537 ETHERNET
Hit any key to stop autoboot:  2
\end{verbatim}
Der Benutzer hat zwei Sekunden Zeit, eine beliebige Taste zu drücken damit der Bootvorgang gestoppt wird und man auf die Kommandozeile von U-Boot gelangt.\\

Das Kernel Image kann nun auf das LCV Board transferiert werden:
\begin{verbatim}
u-boot> tftp 2000000 uImage                                                    
\end{verbatim}
Der erste Parameter steht für die Adresse im RAM, an welcher der Kernel temporär gespeichert werden soll. Das zweite Argument ist der Name des Kernels auf dem TFTP Server.
Ist der Vorgang erfolgreich, erscheint folgender Output auf der Kommandozeile:
\begin{verbatim}
Using BF537 ETHERNET device                                                    
TFTP from server 192.168.0.3; our IP address is 192.168.0.15                   
Filename 'uImage'.                                                             
Load address: 0x2000000                                                        
Loading: ################################################################# 
         #################################################################     
         #################################################################     
         #################################################################     
         #################################################################     
         #################################################################     
         #################################################################     
         #################################################################     
         #################################################################     
         ###################################                                   
done                                                                           
Bytes transferred = 3173635 (306d03 hex)
\end{verbatim}

Es empfiehlt sich, den heruntergeladenen Kernel zu prüfen, bevor man ihn ins Flash kopiert. Dafür kann folgendes Kommando verwendet werden:
\begin{verbatim}
u-boot> iminfo 2000000                                                         
                                                                               
## Checking Image at 02000000 ...                                              
   Image Name:   uClinux Kernel and ext2                                       
   Image Type:   Blackfin Linux Kernel Image (gzip compressed)                 
   Data Size:    3173571 Bytes =  3 MB                                         
   Load Address: 00001000                                                      
   Entry Point:  00158000                                                      
   Verifying Checksum ... OK                                                   
\end{verbatim}

Der Kernel kann nun direkt vom RAM gebootet werden, das hat den Vorteil, dass der alte Kernel im Flash Speicher verbleibt und bei einem Reset des LCV Boards automatisch wieder gebootet wird:
\begin{verbatim}
u-boot> bootm 2000000
\end{verbatim}

Will man allerdings den Kernel fest installieren, beziehungsweise in den Flash Speicher kopieren, kann das mit dem folgenden Kommando bewerkstelligt werden:

\begin{alltt}
u-boot> cp.b 2000000 10020000 \$(filesize)
\end{alltt}

Der Schreibvorgang benötigt ca. 3 Minuten, während dieser Zeit darf die Stromversorgung des LCV Boards nicht unterbrochen werden.\\
Der neue Kernel ist danach im Flash Speicher abgelegt und wird bei einem Reset des LCV Boards automatisch gebootet.

